﻿// ===============================================================================
//  Copyright © ymind.net. All rights reserved .
//  官方网站：http://ymind.net/
//  版权所有：彦铭工作室 老陈出品
// ===============================================================================

using System;
using System.Linq;
using System.Runtime.InteropServices;

namespace Lcsoft.TemplateEngine.Core
{
	/// <summary>
	/// 表示一个语言项。
	/// </summary>
	[ComVisible(true)]
	[Serializable]
	public struct LanguageItem : IEquatable<LanguageItem>
	{
		private static readonly bool _emptyValueFilled;

		/// <summary>
		/// 表示空语言项。此字段为只读。
		/// </summary>
		public static readonly LanguageItem Empty;

		/// <summary>
		/// 初始化语言项的默认值。
		/// </summary>
		static LanguageItem()
		{
			Empty = new LanguageItem(String.Empty, String.Empty, LanguagePack.Empty);

			_emptyValueFilled = true;
		}

		/// <summary>
		/// 初始化 <see cref="LanguageItem"/> 类的新实例。
		/// </summary>
		/// <param name="name">指定语言项的名称。</param>
		/// <param name="value">指定语言项的内容。</param>
		/// <param name="pack">指定语言项所属的语言包的实例。</param>
		public LanguageItem(string name, string value, LanguagePack pack) : this()
		{
			if (_emptyValueFilled)
			{
				if (name == null) throw new ArgumentNullException("name");
				if (name.Length == 0) throw new ArgumentOutOfRangeException("name");

				if (value == null) throw new ArgumentNullException("value");
				if (value.Length == 0) throw new ArgumentOutOfRangeException("value");
			}

			this.Name = name;
			this.Value = value;
			this.OwnerPack = pack;
			this.HasLabel = false;
			this.NestedValue = String.Empty;
			this.IsAuto = false;

			// 处理嵌套标签
			if (this.Value.IndexOf("{$", StringComparison.Ordinal) == -1 && this.Value.IndexOf("{#", StringComparison.Ordinal) == -1) return;
			if (this.OwnerPack == LanguagePack.Empty) return;

			this.HasLabel = true;

			//{$LangName$}	{#Cache.Count#}
			//				{#Cache.Count#}
			var iValue = this.Value;
			iValue = iValue.Replace("{$", "[LCSOFT.TEMPLATEENGINE:LANGUAGEITEM]{$");
			iValue = iValue.Replace("{#", "[LCSOFT.TEMPLATEENGINE:LANGUAGEITEM]{#");
			iValue = iValue.Replace("$}", "$}[LCSOFT.TEMPLATEENGINE:LANGUAGEITEM]");
			iValue = iValue.Replace("#}", "#}[LCSOFT.TEMPLATEENGINE:LANGUAGEITEM]");

			// 抽取嵌套标签
			var codes = iValue.Split(new[] { "[LCSOFT.TEMPLATEENGINE:LANGUAGEITEM]" }, StringSplitOptions.None);
			var i = 0;

			foreach (var code in codes)
			{
				string nvalue;

				if ((code.StartsWith("{$") && code.EndsWith("$}")) || (code.StartsWith("{#") && code.EndsWith("#}"))) nvalue = code;
				else
				{
					i++;

					var langName = String.Format("[LCSOFT.TEMPLATEENGINE:AUTOCREATEITEM_{0}_{1}]", this.Name, i);

					// 为纯文本创建新的语言项
					var langCode = code;

					var list = this.OwnerPack.Items.Where(item => item.Value == langCode).ToList();

					if (list.Count == 0)
					{
						var item = new LanguageItem(langName, code, this.OwnerPack) {
							IsAuto = true
						};

						this.OwnerPack.Items.Add(item);
					}
					else langName = list.First().Name;

					nvalue = String.Format("{{$Lang[{0}]$}}", langName);
				}

				if (String.IsNullOrEmpty(this.NestedValue)) this.NestedValue = nvalue;
				else this.NestedValue += nvalue;
			}
		}

		/// <summary>
		/// 获取该语言项的名称。
		/// </summary>
		public string Name { get; private set; }

		/// <summary>
		/// 获取该语言项的内容。
		/// </summary>
		public string Value { get; private set; }

		/// <summary>
		/// 获取一个值，该值表示当前语言项是否包含嵌套的标签。
		/// </summary>
		public bool HasLabel { get; private set; }

		/// <summary>
		/// 获取该语言项的替代内容。该内容已经处理了嵌套标签。
		/// </summary>
		public string NestedValue { get; private set; }

		/// <summary>
		/// 获取该语言项所属的语言包的实例。
		/// </summary>
		public LanguagePack OwnerPack { get; private set; }

		/// <summary>
		/// 获取一个值，该值表示当前语言项是否由多语言引擎为嵌套标签自动创建的。
		/// </summary>
		public bool IsAuto { get; private set; }

		#region IEquatable<LanguageItem> Members

		/// <summary>
		/// 返回一个值，该值指示此实例是否与指定的对象相等。
		/// </summary>
		/// <param name="other">要与此实例进行比较的对象。</param>
		/// <returns>如果 <paramref name="other"/> 是 <see cref="LanguageItem"/> 的实例并且等于此实例的值，则为 true；否则为 false。</returns>
		public bool Equals(LanguageItem other) { return Equals(other.Name, this.Name); }

		#endregion

		/// <summary>
		/// 返回一个值，该值指示此实例是否与指定的对象相等。
		/// </summary>
		/// <param name="obj">要与此实例进行比较的对象。</param>
		/// <returns>如果 <paramref name="obj"/> 是 <see cref="LanguageItem"/> 的实例并且等于此实例的值，则为 true；否则为 false。</returns>
		public override bool Equals(object obj)
		{
			if (ReferenceEquals(null, obj)) return false;

			return obj is LanguageItem && this.Equals((LanguageItem)obj);
		}

		/// <summary>
		/// 将当前 <see cref="LanguageItem"/> 对象的值转换为其等效的字符串表示形式。
		/// </summary>
		/// <returns>当前 <see cref="LanguageItem"/> 对象的值的字符串表示形式。</returns>
		public override string ToString() { return this.Name; }

		/// <summary>
		/// 返回此实例的哈希代码。
		/// </summary>
		/// <returns>32 位有符号整数哈希代码。</returns>
		public override int GetHashCode() { return (this.Name != null ? this.Name.GetHashCode() : 0); }

		/// <summary>
		/// 确定 <see cref="LanguageItem"/> 的两个指定的实例是否相等。
		/// </summary>
		/// <param name="left">第一个 <see cref="LanguageItem"/> 的实例。</param>
		/// <param name="right">第二个 <see cref="LanguageItem"/> 的实例。</param>
		/// <returns>如果 <paramref name="left"/> 和 <paramref name="right"/> 表示同一语言包，则为 true；否则为 false。</returns>
		public static bool operator ==(LanguageItem left, LanguageItem right) { return left.Equals(right); }

		/// <summary>
		/// 确定 <see cref="LanguageItem"/> 的两个指定的实例是否不等。
		/// </summary>
		/// <param name="left">第一个 <see cref="LanguageItem"/> 的实例。</param>
		/// <param name="right">第二个 <see cref="LanguageItem"/> 的实例。</param>
		/// <returns>如果 <paramref name="left"/> 和 <paramref name="right"/> 不表示同一语言包，则为 true；否则为 false。</returns>
		public static bool operator !=(LanguageItem left, LanguageItem right) { return !left.Equals(right); }
	}
}
